from general_utilities import *
from map import *
from random import lognormvariate
from screen_info import display

SD_MOVE = 1
SD_BATTLE = 2
SD_PICKUP = 3
SD_CAST = 4
SD_RUSTLE = 5
SD_DADDU_YADDU = 6
SD_CLATTER = 7
SD_SCREECH = 8
SD_HISS = 9
SD_WHOOSH = 10
SD_BIGFEET = 11
SD_SNORE = 12
SD_ROAR = 13
SD_GRUNT = 14
SD_CRASH = 15

class Noise:
  def make(self,d,type,volume,origin,entity_warned_of,audible_to_you):
    # make the noise.
    # Return 1 if a message is printed to the player.
    self.type = type  # a SD_ code from above
    self.volume = volume * random.lognormvariate(0,0.15)
    self.origin = origin.copy() # a Pos
    self.entity_warned_of = entity_warned_of # an entity, anyone who hears will get a threat indication for this entity. Can be None
    if self.entity_warned_of is not None: # handle threat indications
      for entity in d.get_entities_in_nearby_room(origin):
        if not entity.no_longer_here():
          if entity.is_enemy(self.entity_warned_of):
            if self.heard_by(d,entity):
              gr = d.get_group(entity.id.group)
              gr.enemy_seen(d,self.entity_warned_of)
              break
    # handle hearing by character
    character_heard = 0
    if audible_to_you:
      if self.heard_by(d,d.get_character()) and self.type not in d.noise_types_to_suppress:
        character_heard = 1
        volume = self.volume_at(d,d.get_active_pos())
        suppress = 1
        if self.type==SD_MOVE:
          display.send_message("You hear something moving about.")
        elif self.type==SD_BATTLE:
          display.send_message("You hear the sounds of battle in the distance.")
        elif self.type==SD_PICKUP:
          display.send_message("You hear a rustling sound.")
        elif self.type==SD_CAST:
          display.send_message("You hear chanting.")
        elif self.type==SD_RUSTLE:
          display.send_message("You hear a rustling sound.")
        elif self.type==SD_DADDU_YADDU:
          display.send_message("You hear a yell of 'DADDU-YADDU!'")
        elif self.type==SD_CLATTER:
          display.send_message("You hear a menacing clattering noise.")
        elif self.type==SD_SCREECH:
          display.send_message("You hear a piercing screech!")
        elif self.type==SD_HISS:
          display.send_message("You hear a hissing sound, like steam from a kettle.")
        elif self.type==SD_WHOOSH:
          display.send_message("You hear a sudden 'WHOOSH!'")
        elif self.type==SD_BIGFEET:
          display.send_message("You hear a large creature stomping towards you!") 
        elif self.type==SD_SNORE:
          display.send_message("You hear incredibly loud snoring in the distance.")
        elif self.type==SD_ROAR:
          display.send_message("You hear an enraged roar!")
        elif self.type==SD_GRUNT:
          display.send_message("You hear a brutish grunt.")
        elif self.type==SD_CRASH:
          display.send_message("You hear a loud crash!")          
        if suppress:
          d.noise_types_to_suppress.append(self.type)
    return character_heard
  
  def heard_by(self,d,entity):
    volume = self.volume_at(d,entity.pos)
    if not d.l.room_at(entity.pos).ever_visited:
      volume = volume * 0.5
    threshold = (1.0/entity.info().hearing)
    heard = (volume >= threshold)
    #if heard:
    #  print "sound of type",self.type,"heard by",entity.name,"volume",volume,"threshold",threshold
    return heard
      
  def volume_at(self,d,pos):
    # 0 means not heard, higher numbers mean volume at destination
    if self.origin.level<>pos.level:
      return 0
    if self.origin.same_room(pos):
      distance = self.origin.distance_within_room(pos)
    else:
      if abs(self.origin.r_down - pos.r_down) + abs(self.origin.r_right - pos.r_right) == 1:
        this_room = d.l.room_at(self.origin)
        if self.origin.r_down > pos.r_down:
          near_door_pos = this_room.get_mid_wall(DIR_UP)
        elif self.origin.r_down < pos.r_down:
          near_door_pos = this_room.get_mid_wall(DIR_DOWN)          
        elif self.origin.r_right > pos.r_right:
          near_door_pos = this_room.get_mid_wall(DIR_LEFT)          
        elif self.origin.r_right < pos.r_right:
          near_door_pos = this_room.get_mid_wall(DIR_RIGHT)                            
        far_door_pos = d.l.tile_at(near_door_pos).to_pos
        if far_door_pos is None:
          return 0         
        distance = 10 + self.origin.distance_within_room(near_door_pos) + far_door_pos.distance_within_room(pos)
      else:
        return 0
    stealth_mult = self.entity_warned_of.stealth_sound_multiplier()
    heard_volume = stealth_mult * self.volume * 4.5 / max(4.5,3+distance)
    # print self.type,self.volume,pos,heard_volume
    return heard_volume

# do some psyco bindings 
psyco.bind(Noise.make)
psyco.bind(Noise.heard_by)
psyco.bind(Noise.volume_at)